﻿using WpfModelEditor.Core.Plugins;
using System.Diagnostics;
using System.Threading.Tasks;
using System;
using HelixToolkit.Wpf.SharpDX;
using System.Windows;
using Microsoft.Win32;
using System.Linq;
using System.IO;
using HelixToolkit.Wpf.SharpDX.Animations;
using System.Collections.Generic;
using MahApps.Metro.IconPacks;
using Fluent;
using System.Text;

namespace FilePlugin
{
    public class FilePluginImpl : IPlugin
    {
        private string OpenFileFilter { get; set; }
        private string SaveFileFilter { get; set; }

        private static FilePluginImpl _instance = null;
        public static FilePluginImpl Instance { get { return _instance; } }
        public FilePluginImpl()
        {
            Debug.Assert(_instance == null);
            _instance = this;
        }
        public int Order { get { return 10; } }
        public IHost Host { get; private set; }
        public void Initialize(IHost host)
        {
            Host = host;
            InitFormats();
            var tab = host.UI.GetOrCreateRibbonTabItem("开始");
            var group = new RibbonGroupBox
            {
                Header = "文件",
            };
            tab.Groups.Add(group);
            var splitButton = new Fluent.Button
            {
                Header = "清空",
                SizeDefinition = RibbonControlSizeDefinition.FromString("Large"),
                LargeIcon = new PackIconMaterial { Kind = PackIconMaterialKind.OpenInNew },
                Icon = new PackIconMaterial { Kind = PackIconMaterialKind.OpenInNew },
            };
            splitButton.Click += NewButton_Click;
            group.Items.Add(splitButton);
            splitButton = new Fluent.Button
            {
                Header = "打开",
                SizeDefinition = RibbonControlSizeDefinition.FromString("Large"),
                LargeIcon = new PackIconMaterial { Kind = PackIconMaterialKind.OpenInApp },
                Icon = new PackIconMaterial { Kind = PackIconMaterialKind.OpenInApp },
            };
            splitButton.Click += OpenMenu_Click;
            group.Items.Add(splitButton);

            splitButton = new Fluent.Button
            {
                Header = "导出",
                SizeDefinition = RibbonControlSizeDefinition.FromString("Large"),
                LargeIcon = new PackIconMaterial { Kind = PackIconMaterialKind.FileExport },
                Icon = new PackIconMaterial { Kind = PackIconMaterialKind.FileExport },
            };
            splitButton.Click += ExportMenu_Click;
            group.Items.Add(splitButton);

            var btn = new Fluent.Button
            {
                Header = "清空"
            };
            btn.Icon = new PackIconMaterial { Kind = PackIconMaterialKind.OpenInNew };
            btn.Click += NewButton_Click;
            host.UI.BackstageTabControl.Items.Add(btn);

            btn = new Fluent.Button
            {
                Header = "打开"
            };
            btn.Icon = new PackIconMaterial { Kind = PackIconMaterialKind.OpenInApp };
            btn.Click += OpenMenu_Click;
            host.UI.BackstageTabControl.Items.Add(btn);

            btn = new Fluent.Button
            {
                Header = "导出"
            };
            btn.Icon = new PackIconMaterial { Kind = PackIconMaterialKind.FileExport };
            btn.Click += ExportMenu_Click;
            host.UI.BackstageTabControl.Items.Add(btn);
        }
        private void InitFormats()
        {
            {
                var formats = new Dictionary<string, string>();
                foreach (var plugin in Host.IoPlugins)
                {
                    foreach (var f in plugin.SupportedImportFormats)
                    {
                        if (!formats.ContainsKey(f.Ext))
                            formats.Add(f.Ext, f.Name);
                    }
                }
                var sb = new StringBuilder();
                sb.Append($"所有支持的格式 | ");
                foreach (var s in formats)
                {
                    sb.Append($"*{s.Key};");
                }
                sb.Append($"|");
                foreach (var s in formats)
                {
                    sb.Append($"{s.Value}(*{s.Key})|*{s.Key}|");
                }
                OpenFileFilter = sb.ToString(0, sb.Length - 1);
            }
            {
                var formats = new Dictionary<string, string>();
                foreach (var plugin in Host.IoPlugins)
                {
                    foreach (var f in plugin.SupportedExportFormats)
                    {
                        if (!formats.ContainsKey(f.Ext))
                            formats.Add(f.Ext, f.Name);
                    }
                }
                var sb = new StringBuilder();
                foreach (var s in formats)
                {
                    sb.Append($"{s.Value}(*{s.Key})|*{s.Key}|");
                }
                SaveFileFilter = sb.ToString(0, sb.Length - 1);
            }
        }
        private void NewButton_Click(object sender, RoutedEventArgs e)
        {
            Host.Clear();
        }

        private void ExportMenu_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            var index = SaveFileDialog(SaveFileFilter, out var path);
            if (!string.IsNullOrEmpty(path) && index >= 0)
            {
                var animations = new HashSet<Animation>();
                foreach (var ani in Host.Animations)
                {
                    if (ani is KeyFrameUpdater)
                    {
                        animations.Add((ani as KeyFrameUpdater).Animation);
                    }
                    else if (ani is NodeAnimationUpdater)
                    {
                        animations.Add((ani as NodeAnimationUpdater).Animation);
                    }
                    else if (ani is MorphTargetKeyFrameUpdater)
                    {
                        animations.Add((ani as MorphTargetKeyFrameUpdater).animation);
                    }
                    else if (ani is AnimationGroupUpdater)
                    {
                        //animations.Add((ani as AnimationGroupUpdater).Animation);
                    }
                }
                var scene = new Scene
                {
                    Animations = animations.ToList(),
                    Root = Host.Model.SceneNode
                };
                Host.IsBusy = true;
                Task.Run(() =>
                {
                    var ext = Path.GetExtension(path).ToLower();
                    LoadSaveResult res = LoadSaveResult.NotSupport;
                    foreach (var plugin in Host.IoPlugins)
                    {
                        res = plugin.Save(path, ext, scene);
                        if (res != LoadSaveResult.NotSupport)
                        {
                            break;
                        }
                    }
                    if (res == LoadSaveResult.NotSupport)
                        throw new Exception($"不支持的文件格式");
                    if (res != LoadSaveResult.Success)
                        throw new Exception($"导出文件失败");
                }).ContinueWith((result) =>
                {
                    Host.IsBusy = false;
                    if (result.IsCompleted && result.Status == TaskStatus.RanToCompletion)
                    {

                    }
                    else if (result.IsFaulted && result.Exception != null)
                    {
                        if (result.Exception.InnerException != null)
                            MessageBox.Show(result.Exception.InnerException.Message);
                        else
                            MessageBox.Show(result.Exception.Message);
                    }
                }, TaskScheduler.FromCurrentSynchronizationContext());
                return;
            }
        }

        private void OpenMenu_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            if (Host.IsBusy)
            {
                return;
            }
            string path = OpenFileDialog(OpenFileFilter);
            if (path == null)
            {
                return;
            }
            Host.StopAnimation();
            Host.IsBusy = true;
            Task.Run(() =>
            {
                var ext = Path.GetExtension(path).ToLower();
                Scene scene = null;
                LoadSaveResult res = LoadSaveResult.NotSupport;
                foreach (var plugin in Host.IoPlugins)
                {
                    res = plugin.Load(path, ext, out scene);
                    if (res != LoadSaveResult.NotSupport)
                    {
                        break;
                    }
                }
                if (res == LoadSaveResult.NotSupport)
                    throw new Exception($"不支持的文件格式");
                if (res != LoadSaveResult.Success)
                    throw new Exception($"加载文件失败");

                scene.Root.Attach(Host.EffectsManager);
                scene.Root.UpdateAllTransformMatrix();
                return scene;
            }).ContinueWith((result) =>
            {
                Host.IsBusy = false;
                if (result.IsCompleted && result.Status == TaskStatus.RanToCompletion)
                {
                    var scene = result.Result;
                    if (scene != null)
                    {
                        Host.Model.AddNode(scene.Root);
                        if (scene.HasAnimation)
                        {
                            var dict = scene.Animations.CreateAnimationUpdaters();
                            foreach (var ani in dict.Values)
                            {
                                Host.Animations.Add(ani);
                            }
                        }
                        Host.FireEvent("SceneChanged", result.Result);
                    }
                }
                else if (result.IsFaulted && result.Exception != null)
                {
                    if (result.Exception.InnerException != null)
                        MessageBox.Show(result.Exception.InnerException.Message);
                    else
                        MessageBox.Show(result.Exception.Message);
                }
            }, TaskScheduler.FromCurrentSynchronizationContext());
        }

        private string OpenFileDialog(string filter)
        {
            var d = new OpenFileDialog();
            d.CustomPlaces.Clear();

            d.Filter = filter;

            if (!d.ShowDialog().Value)
            {
                return null;
            }

            return d.FileName;
        }
        private int SaveFileDialog(string filter, out string path)
        {
            var d = new SaveFileDialog();
            d.Filter = filter;
            if (d.ShowDialog() == true)
            {
                path = d.FileName;
                return d.FilterIndex - 1;//This is tarting from 1. So must minus 1
            }
            else
            {
                path = "";
                return -1;
            }
        }

        public void OnEvent(string eventName, object data)
        {
        }

        public void Clearup()
        {
        }
    }
}